﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IWMAG.Scripting.Compiler.Helpers;
using IWMAG.Scripting.AST.ObjectModel;
using System.Diagnostics;
using IWMAG.Scripting.AST.Declarations;
using IWMAG.Scripting.Types;
using IWMAG.Scripting.Helpers;

namespace IWMAG.Scripting.Compiler {
    [Serializable]
    public class ParseException : Exception {
        public ParseException() { }
        public ParseException(string message) : base(message) { }
        public ParseException(string message, Exception inner) : base(message, inner) { }
        protected ParseException(
          System.Runtime.Serialization.SerializationInfo info,
          System.Runtime.Serialization.StreamingContext context)
            : base(info, context) { }
    }

    internal partial class Parser {
        protected List<Lexeme> Lexemes;
        protected TokenMapping Tokens = new TokenMapping();
        protected OperatorMapping Operators = new OperatorMapping();
        protected int Ptr = 0;
        protected bool Failed;
        public List<IUserInfo> ErrorList { get; set; }

        protected Lexeme Here {
            get {
                if (Ptr < Lexemes.Count)
                    return Lexemes[Ptr];
                return default(Lexeme);
            }
        }

        public Parser() {
            ErrorList = new List<IUserInfo>();
        }

        public ProgramDeclaration Parse(string s) {
            try {
                var lexer = (new Lexer(s, ErrorList));
                var stream = lexer.Lex();
                Lexemes = new List<Lexeme>(stream);
            } catch (LexException) {
                Debug.Assert(ErrorList.Count > 0);
                Lexemes = null;
            }

            if (Lexemes == null) {
                return null;
            }

            return Program();
        }

        protected Lexeme Rel(int rel) {
            if (Ptr + rel < Lexemes.Count)
                return Lexemes[Ptr + rel];
            return default(Lexeme);
        }

        protected bool Match(string s) {
            return Match(0, Tokens[s]);
        }

        protected bool Match(Token type) {
            return Match(0, type);
        }

        protected bool Match(int rel, string s) {
            return Match(rel, Tokens[s]);
        }

        protected bool Match(int rel, Token type) {
            return Rel(rel).Type == type;
        }

        protected void Assert(string s) {
            Assert(0, Tokens[s]);
        }

        protected void Assert(Token type) {
            Assert(0, type);
        }

        protected void Assert(int rel, string s) {
            Assert(rel, Tokens[s]);
        }

        protected void Assert(int rel, Token type) {
            if (!Match(rel, type)) {
                ErrorList.Add(new CompileError(String.Format("Expecting {0}, got {1}", type, Here), Here.Line, Here.Column));
                throw new ParseException();
            }
        }
    }
}
